#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include "part.h"
#include "opm.h"
#include "oxc.h"
#include "wss.h"

int set_speed_uart(int fd,int speed){
    struct termios tio;
    if(tcgetattr(fd,&tio)!=0){
        return -1;
    }
    //设置串口波特率
    switch(speed){
        case 2400:
            cfsetispeed(&tio,B2400);
            cfsetospeed(&tio,B2400);
            break;
        case 4800:
            cfsetispeed(&tio,B4800);
            cfsetospeed(&tio,B4800);
            break;
        case 9600:
            cfsetispeed(&tio,B9600);
            cfsetospeed(&tio,B9600);
            break;
        case 115200:
            cfsetispeed(&tio,B115200);
            cfsetospeed(&tio,B115200);
            break;
        case 460800:
            cfsetispeed(&tio,B460800);
            cfsetospeed(&tio,B460800);
            break;
        default:
            cfsetispeed(&tio,B9600);
            cfsetospeed(&tio,B9600);
            break;
    }
    tcflush(fd,TCIFLUSH);

    if(tcsetattr(fd,TCSANOW,&tio)!=0){
        printf("com set error\n");
        return -1;
    }
    return 0;
}

int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop)
{
    struct termios newtio,oldtio;
    if(tcgetattr(fd,&oldtio)!=0){
        return -1;
    }
    memset(&newtio,0,sizeof(newtio));
    //使能串口接收
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;

    newtio.c_lflag &=~ICANON;//原始模式

    //设置串口数据位
    switch(nBits){
        case 7:
            newtio.c_cflag |= CS7;
            break;
        case 8:
            newtio.c_cflag |=CS8;
            break;
    }
    //设置奇偶校验位
    switch(nEvent){
        case 'O':
            newtio.c_cflag |= PARENB;
            newtio.c_cflag |= PARODD;
            newtio.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'E':
            newtio.c_iflag |= (INPCK | ISTRIP);
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            break;
        case 'N':
            newtio.c_cflag &=~PARENB;
            break;
    }
    //设置串口波特率
    switch(nSpeed){
        case 2400:
            cfsetispeed(&newtio,B2400);
            cfsetospeed(&newtio,B2400);
            break;
        case 4800:
            cfsetispeed(&newtio,B4800);
            cfsetospeed(&newtio,B4800);
            break;
        case 9600:
            cfsetispeed(&newtio,B9600);
            cfsetospeed(&newtio,B9600);
            break;
        case 115200:
            cfsetispeed(&newtio,B115200);
            cfsetospeed(&newtio,B115200);
            break;
        case 460800:
            cfsetispeed(&newtio,B460800);
            cfsetospeed(&newtio,B460800);
            break;
        default:
            cfsetispeed(&newtio,B9600);
            cfsetospeed(&newtio,B9600);
            break;
    }
    //设置停止位
    if(nStop == 1)
        newtio.c_cflag &= ~CSTOPB;
    else if(nStop == 2)
        newtio.c_cflag |= CSTOPB;
    newtio.c_cc[VTIME] = 1;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);

    if(tcsetattr(fd,TCSANOW,&newtio)!=0){
        printf("com set error\n");
        return -1;
    }
    return 0;
}

int read_tty(device* p_device,char *recv_buf,int len,int sec,int usec){
    int retval;
    fd_set rfds;
    struct timeval tv;
    int ret = 0;

    tv.tv_sec = sec;//set the rcv wait time
    tv.tv_usec = usec;//1000000us = 1s

    FD_ZERO(&rfds);
    FD_SET(p_device->uart_fd,&rfds);
    retval = select(p_device->uart_fd+1,&rfds,NULL,NULL,&tv);
    if(retval > 0){
        ret= read(p_device->uart_fd,recv_buf,len);
    }
    if(ret > 0){
        printf_comm_flag(COM_RX,p_device->print_flag,p_device->device_name,recv_buf,len);
    }
    return ret;
}

int write_tty(device* p_device,char *send_buf,int len){
    int ret = 0;
    if(send_buf == NULL) return 0;
    // printf_comm_flag(COM_TX,p_device->print_flag,p_device->device_name,send_buf,len);
    ret = write(p_device->uart_fd,send_buf,len);
    return ret;
}

int query_tty_time(device* p_device,char* send_buf,int slen,char* recv_buf,int rlen,int sec,int usec,clock_t* usage_time){
    clock_t start,end;
    int ret; 
    start = clock(); 
    ret = query_tty(p_device,send_buf,slen,recv_buf,rlen,sec,usec);
    end = clock();
    if(usage_time) *usage_time = end - start;
}

int query_tty(device* p_device,char* send_buf,int slen,char* recv_buf,int rlen,int sec,int usec){
    int ret = 0;
    if(write_tty(p_device,send_buf,slen)){
        ret = read_tty(p_device,recv_buf,rlen,sec,usec);
    }
    return ret;
}

int open_uart(char* uart_no,int speed,int bits,char event,int stop){
    int fd = 0;
    fd = open( uart_no,O_RDWR|O_NOCTTY );
    if(fd == -1) return -1;
    if(set_opt(fd,speed,bits,event,stop) == -1){
        close(fd);
        return -1;
    }
    return fd;
}

void close_uart(int fd){
    if(fd > 0) close(fd);
}

void part_alarm_register(device_alarm_list* p_list){
    wss_alarm_register(p_list);
    opm_alarm_register(p_list);
    oxc_alarm_register(p_list);    
}

cJSON* part_default(int cmd_id){
    wss_parse(cmd_id,NULL);
    oxc_parse(cmd_id,NULL);
    return response_packet(cmd_id,NO_ERROR,NULL,0);
}